/**
 * 
 */
package jpave.dataholders;

import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Vector;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import util.methods.StringHelpers;
import util.Debug.ErrorReport;

public class MainData implements Serializable
{
	public MainData ()
	{
		contigMap = new TreeMap<String, ContigData> ();
	}

	/**
	 * ContigListTab.addClusterTab
	 * MainTopRowTab.addNewTab
	 * ContigPairListTab.addPairViewTab
	 * Add an empty contig to the cluster - for multiple contigs 
	 */
    public void addContigStub ( String strContigID )
    {
        ContigData stub = new ContigData ();
        stub.setContigID( strContigID);
        addContig ( stub );
    }
    
    /**
     * ClusterData.addContigStub
     * JPaveFrame.addNewContig
     * CAP3AceFileReader.readClusterFrom
     * Called directly for one contig
     */
	public void addContig ( ContigData theContig )
	{
		// not used but still breaks something if removed
		if ( theContig.getNumSequences() == 1 )++nNumSingletons;
		else ++nNumContigs;
		nNumESTs += theContig.getNumSequences();	
		if (strBestMatch.equals("")) 
			strBestMatch = theContig.getBestMatch();
		
		// Add to the map from ContigID to the ContigData object
		if ( contigMap.put( theContig.getContigID(), theContig ) != null )
			throw new RuntimeException ( "Found two contigs named " + theContig.getContigID() + "." );
	}
	// PairwiseAlignmentData
	public ContigData findContig ( String strID )
	{
		return contigMap.get( strID );
	}
	
	// JPaveDBWrapper
	//3-4-10 Mark Modified to adjust cluster counts
	public void replaceContig ( String strID, ContigData newContig )
	{
		contigMap.put(strID, newContig);
	}
	
	public TreeSet<String> getContigIDSet ()
	{
		TreeSet<String> returnSet = new TreeSet<String> ();
		
		// Iterate over the list of contigs
		Iterator<Map.Entry<String, ContigData>> iter = contigMap.entrySet().iterator();
		while ( iter.hasNext() )
		{
			// Add the ID to the set
			Map.Entry<String, ContigData> entry = iter.next ();
			ContigData curContig = entry.getValue();
			returnSet.add( curContig.getContigID() );
		}	
		
		return returnSet;
	}
	// MultiAlignmentPanel.createESTToolbar
	public ContigData getContigAt ( int i )
	{
		if ( i < 0 || i > getTotalContigs () )
			return null;
		
		Iterator<ContigData> iter = getContigIterator ();
		ContigData returnContig = null;
		for ( int j = 0; j <= i; ++j )
			returnContig = iter.next();	
		
		return returnContig;
	}
	
	public String getCtgIDAt ( int i )
	{
		if ( i < 0 || i > getTotalContigs () )
			return null;
		
		Iterator<ContigData> iter = getContigIterator ();
		ContigData returnContig = null;
		for ( int j = 0; j <= i; ++j )
			returnContig = iter.next();	
		
		return returnContig.getContigID();
	}
	// ClusterViewTab.loadESTsAndDraw
	public void removeBuried() {
		Iterator<ContigData> iter = contigMap.values().iterator();
		while(iter.hasNext())
			iter.next().removeBuriedSequences();
	}
	
	public Iterator<ContigData> getContigIterator ( ) { return contigMap.values().iterator(); }

	public String getClusterID ( ) { return strClusterID; }
	public void setClusterID ( String str ) { strClusterID = str; }
	
	public String getBestMatch ( ) { return strBestMatch; }
	public void setBestMatch ( String str ) { strBestMatch = str; }
	
	public double getMinEValue ( ) { return dMinEValue; }
	public String getMinEValueAsString ( ) { return evalueToString (dMinEValue); }
	
	public double getMaxEValue ( ) { return dMaxEValue; }
	public String getMaxEValueAsString ( ) { return evalueToString (dMaxEValue); }

	static private String evalueToString ( double d )
	{
		if ( Math.abs( d ) != Double.MAX_VALUE )
			return Double.toString( d ); 
		else
			return "";
	}
			
	public int getNumESTs ( ) { return nNumESTs; };	
	public int getNumSingletons ( ) { return nNumSingletons; }
	public int getNumNonSingletons ( ) { return nNumContigs; }
	
	// alignment types
	final public static int NO_CONTIGS = 0;
	final public static int ALIGNMENT_EST = 1;
	final public static int ALIGNMENT_TO_PROTEIN = 2;	
	final public static int ALIGNMENT_CONSENSUS_PAIR = 3;	
	
	public int getAlignmentType ( ) 
	{
		if ( contigMap == null || contigMap.isEmpty() )
			return NO_CONTIGS;
		if ( nNumConsensusAlignments > 0 )
			return ALIGNMENT_CONSENSUS_PAIR;
		if ( nNumProteinAlignments > 0 )
			return ALIGNMENT_TO_PROTEIN;
		return ALIGNMENT_EST;
	}
	
	public int getTotalContigs ( ) { return nNumSingletons + nNumContigs; };
		
	public void clear()
	{
		if(contigMap != null) contigMap.clear();
	}
	
	/**
	 * @return true if contig loaded from the database, false if it is generated from CAP3/Phrap
	 */
	public boolean isFromLib() { return sourceContig.equals(""); }
	
	public String writeToFile(String strDirName, final Vector<String> source, int ID)
	{
		String fileName = "";
		tabID = ID;
		
		//TODO Support multiple contigs... right now just one supported
		if(contigMap.size() > 1 )	//if more than one contig, then exit: not supported yet
			return "";

		//Set source name for contig
		sourceContig = source.get(0);
	
		fileName = strDirName + sourceContig + "_" + tabID + ".contig";
		
		try {
			FileOutputStream fos = new FileOutputStream(fileName);
			ObjectOutputStream out = new ObjectOutputStream(fos);
			out.writeObject(this);
		} catch (FileNotFoundException e) {
			String s = "Error: writing to file";
			System.err.println(s);
			ErrorReport.reportError(e, s);
		}
		catch (IOException e) {
			String s = "Error: writing to file";
			System.err.println(s);
			ErrorReport.reportError(e, s);
		}
		return fileName;
	}
	
	public String getSourceName() { return sourceContig;}
	public int getTabID() { return tabID; }
	
	/**
	 * Load a contig from file
	 * @param fileName source location
	 * @return loaded contig
	 */
	public static MainData loadFromFile(String fileName)
	{
		MainData temp = new MainData();
		String s = "Error: loading file " + fileName;
		
		try
		{
			FileInputStream fis = new FileInputStream(fileName);
			ObjectInputStream in = new ObjectInputStream(fis);
			
			temp = (MainData)in.readObject();
		}
		catch (FileNotFoundException e) {
			System.err.println(s);
			ErrorReport.reportError(e, s);
		}
		catch (IOException e) {
			System.err.println(s);
			ErrorReport.reportError(e,s);
		} catch (ClassNotFoundException e) {
			System.err.println(s);
			ErrorReport.reportError(e, s);
		}
		
		return temp;
	}
	// XXX serious kludge so pairs knows the number of shared hits
	// before aligning. 
	public BlastHitData getSharedHits() { return sharedHits;}
	public void setSharedHits(BlastHitData b) {
		sharedHits = b;
	}
	BlastHitData sharedHits = null;
	
	//added mrw 11/17/09 - need to save CAP/PHRAP clusters to a temp file to retain data
	String sourceContig = "";
	int tabID = -1;
	
	int nNumESTs = 0;
	int nNumSingletons = 0;
	int nNumContigs = 0;
	int nNumConsensusAlignments = 0;
	int nNumProteinAlignments = 0;
	
	TreeMap<String, ContigData> contigMap = null;
	
	String strBestMatch = "";
	double dMinEValue = Double.MAX_VALUE;
	double dMaxEValue = -Double.MAX_VALUE;
	
	String strClusterID = "";
    private static final long serialVersionUID = 1;
}